﻿using System;
using System.Collections.Generic;
using BobcatMultiTouch;
using CNShapes;
using CNShapeViewer;
using BobcatUtility;

namespace CNShapeEditor
{
    /// <summary>
    /// Base class for all shape-editing (and related) actions.
    /// </summary><remarks>
    /// We use this base class to support the command-pattern. In addition
    /// to the standard undo() and redo() methods it also specifies other
    /// methods that are used for the shape-drawing application.
    /// 
    /// Receives touch events
    /// ---------------------
    /// In the drawing app, an action may not be a simple create-and-fire
    /// event. An action may take some time and responding to ongoing touch
    /// events while the action takes place. This includes drawing shapes, 
    /// dragging objects etc. So instead of creating an action and firing it, 
    /// we create an "active action" which receives and manages the touch events.
    /// 
    /// ActionCompletedEvent
    /// --------------------
    /// As actions may take some time (see above) we need to be able to notify other 
    /// parts of application when the action is complete. We do this by firing the
    /// ActionCompletedEvent.
    /// </remarks>
    public abstract class Action
    {
        #region Events

        /// <summary>
        /// Args passed to action-completed-events.
        /// </summary>
        public class Args : EventArgs
        {
        }

        /// <summary>
        /// Event raised when the action has completed.
        /// </summary>
        public event EventHandler<Args> ActionCompletedEvent;

        /// <summary>
        /// Derived classes can call this to raise the ActionCompletedEvent.
        /// </summary>
        protected void raiseActionCompletedEvent()
        {
            Utility.CrossThreadInvoke(ActionCompletedEvent, this, new Args());
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Initializes the action with other objects it may need ("model" and "view").
        /// </summary>
        public void initialize(Page page, ShapeEditorControl shapeEditorControl)
        {
            // We store the references to the model and view...
            m_Page = page;
            m_ShapeEditorControl = shapeEditorControl;
            m_ShapeViewerControl = shapeEditorControl.ShapeViewer;

            // We call initialize in the derived class...
            initialize();
        }

        #endregion

        #region Abstract methods

        /// <summary>
        /// Initializes a derived object. Called after the initialize in this base class.
        /// </summary>
        public abstract void initialize();

        /// <summary>
        /// Returns a string description of the action that can be used (for example) as a tooltip in a toolbar.
        /// </summary>
        public abstract string getDescription();

        /// <summary>
        /// Returns true if this action can be undone, false otherwise.
        /// We generally want to support undo and redo for actions that affect the model
        /// (i.e. the picture) such as drawing, but not ones that affect the view such as
        /// moving or zooming. If this methods returns false, then the action will not
        /// be added to the undo stack.
        /// </summary>
        public abstract bool supportsUndo();

        /// <summary>
        /// Undoes the action (and stores the data necessary to redo it again later).
        /// </summary>
        public abstract void undo();

        /// <summary>
        /// Does the action again (after an undo).
        /// </summary>
        public abstract void redo();

        /// <summary>
        /// Called when a touch-down event occurs.
        /// </summary>
        public abstract void onTouchDown(TouchArgs touchArgs);

        /// <summary>
        /// Called when a touch-move event occurs.
        /// </summary>
        public abstract void onTouchMove(TouchArgs touchArgs);

        /// <summary>
        /// Called when a touch-up event occurs.
        /// </summary>
        public abstract void onTouchUp(TouchArgs touchArgs);

        #endregion

        #region Protected data

        protected Page m_Page = null; // The "model" we draw to.
        protected ShapeEditorControl m_ShapeEditorControl = null; // } These two classes make up the "view". They are 
        protected ShapeViewerControl m_ShapeViewerControl = null; // } useful to translate screen coords to shape coords, etc.

        #endregion

    }
}
